home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BOI200P.ZIP / ASYNC.PAS next >
Pascal/Delphi Source File  |  1992-12-14  |  13KB  |  395 lines

  1. { $D-}  { Debug Information Off }
  2. { $S-}  { Stack Checking Off    }
  3. {$V-}  { String Checking Off   }
  4. {$F+}
  5.  
  6. Unit Async;
  7. { Part of BBS Onliner Interface }
  8. { Copyright (C) 1990, 1992 Andrew J. Mead
  9.   All Rights Reserved. }
  10.  
  11. { original version 9/5/90
  12.   history found in IOLIB.PAS
  13.   4/ 7/91  DropCarrier modified (dolocal condition added)
  14.   4/16/91  CallOldInt added
  15.  
  16.   For more information regarding FOSSIL function calls, you can obtain
  17.   PASFOSS1.ZIP from me.  It is a FreeWare Pascal source API of FOSSIL
  18.   revision 5 calls.
  19.  
  20. }
  21.  
  22. INTERFACE
  23.  
  24. Function CARRIER : boolean;                  { Carrier Detect function }
  25. Procedure DROPCARRIER;                       { Drop Carrier }
  26. Procedure ASYNCINT; Interrupt;           { won't work if not in interface??? }
  27. Procedure SENDCHAR(outchar : char);          { Comport Output Routine }
  28. Function CHARREADY : boolean;                { Character Ready for Input }
  29. Function READBUFFER : char;                  { Get Character from buffer }
  30. Procedure CLEARINBUFFER;                     { Empty input buffer }
  31. Procedure SETBUFFERSIZE(newsize : integer);  { Set buffer size, defaul = 1k }
  32. Function INTINIT : byte;                     { Install Comport Interrupt }
  33.  
  34. IMPLEMENTATION
  35.  
  36. Uses
  37.   boidecl,
  38.   iolib,
  39.   dos;
  40.  
  41. Const
  42.   null         = #0;
  43.   icom_maxbuff = 1024;  { circular input buffer maximum size }
  44.  
  45.                   { UART - Universal Asynchronious Receiver/Transmitter    }
  46.   THRoff  = $00;  { 8250 UART Transmitter Holding Register offset          }
  47.   RBRoff  = $00;  { 8250 UART Receiver Buffer Register offset              }
  48.  
  49.   DLLoff  = $00;  { 8250 UART Divisor Latch Least Significant Byte offset  }
  50.   DLMoff  = $01;  { 8250 UART Divisor Latch Most Significant Byte offset   }
  51.  
  52.   IERoff  = $01;  { 8250 UART Interrupt Enable Register offset             }
  53.   IIRoff  = $02;  { 8250 UART Interrupt Identification Register offset     }
  54.   LCRoff  = $03;  { 8250 UART Line Control Register offset                 }
  55.   MCRoff  = $04;  { 8250 UART Modem Control Register offset                }
  56.   LSRoff  = $05;  { 8250 UART Line Status Register offset                  }
  57.   MSRoff  = $06;  { 8250 UART Modem Status Register offset                 }
  58.  
  59.   { IRQ0..7 }
  60.   PICCMD  = $20;  { 8259A Programmable Interrupt Controller Port (Command) }
  61.   PICMSK  = $21;  { 8259A Programmable Interrupt Controller Port (Mask)    }
  62.   { IRQ8..15 }
  63.   PIC2CMD = $A0;  { cascade 8259A PIC (Command)                            }
  64.   PIC2MSK = $A1;  { cascade 8259A PIC (Mask)                               }
  65.  
  66.   RTSbit  = $20;  { Ready To Send bit in LSR }
  67.   CTSbit  = $10;  { Clear To Send bit in MSR }
  68.   DCDbit  = $80;  { Data Carrier Detect (RLSD) bit in MSR }
  69.   DCval   = $08;  { changes carrier detect bit in MSR }
  70.  
  71.   fossint = $14;
  72.  
  73. Type
  74.   portbufftype = array [1..icom_maxbuff] of char;
  75.  
  76. Var
  77.   icom_portbuffer  : portbufftype;  { Circular input buffer }
  78.   icom_bufflimit   : integer;       { Current maximum buffer size }
  79.   icom_buffsize    : integer;       { Number of character in buffer }
  80.   icom_buffend     : integer;       { Index pointing to last char in buffer }
  81.   icom_buffstart   : integer;       { Index pointing to first char in buffer }
  82.   icom_asyncvector : pointer;       { original interrupt vector }
  83.   IIRstatus        : byte;          { 8250 UART IIR status byte }
  84.   LSRstatus        : byte;          { 8250 UART LCR status byte }
  85.  
  86.   foss_regs        : registers;
  87.  
  88. Procedure CALLOLDINT(sub : pointer);
  89.   begin {* CallOldInt *}
  90.     Inline($9C/            { PushF }
  91.         $FF/$5E/$06)       { Call DWord PTR [BP + 6] }
  92.   end;  {* CallOldInt *}
  93.  
  94. Function CARRIER : boolean;
  95.   var
  96.     ctemp : boolean;
  97. { This function will return 'true' if
  98.   a) program is in 'local' mode
  99.   b) carrier detect is disabled (command line option)
  100.   c) carrier (phone line) is detected. }
  101.  
  102.   begin {* fCarrier *}
  103.     if boi_local or (not boi_checkcd) then Carrier := true
  104.     else
  105.       begin
  106.         case boi_cmode of
  107.             com_internal :
  108.                 ctemp := ((port[boi_portadd + MSRoff] and DCDbit) = DCDbit);
  109.             com_fossil :
  110.               begin
  111.                 foss_regs.AH := $03;
  112.                 foss_regs.DX := boi_portnum;
  113.                 Intr(fossint,foss_regs);
  114.                 ctemp := foss_regs.AL and $80 = $80
  115.               end
  116.           end;
  117.         if not ctemp then boi_cdlost := true;
  118.         Carrier := ctemp
  119.       end
  120.   end;  {* fCarrier *}
  121.  
  122. Procedure DROPCARRIER;
  123. { This function will force the modem to hang up the phone.}
  124.   const
  125.     DTRlow = $00;  { force DTR low value }
  126.  
  127.   var
  128.     timebase : longint;
  129.  
  130.   begin {* DropCarrier *}
  131.     if not boi_local then
  132.       begin
  133.         boi_cdlost := true;
  134.         case boi_cmode of
  135.             com_internal :
  136.               begin
  137.                 timebase := boi_timer;
  138.                 repeat port[boi_portadd + MCRoff] := DTRlow
  139.                 until boi_timer >= timebase + 36 { force DTR low for 2 seconds }
  140.               end;
  141.             com_fossil :
  142.               begin
  143.                 foss_regs.AH := $06;
  144.                 foss_regs.AL := DTRlow;
  145.                 foss_regs.DX := boi_portnum;
  146.                 Intr(fossint,foss_regs)
  147.               end
  148.           end
  149.       end
  150.   end;  {* DropCarrier *}
  151.  
  152. Procedure ASYNCINT;
  153.   begin {* AsyncInt *}
  154.     Inline($FB);   { STI }
  155.     if boi_tintr then BOI_Crit;
  156.     IIRstatus := port[boi_portadd + IIRoff];  { read IIR status }
  157.     if ((IIRstatus and $06) = $04) then   { check to see if character waiting }
  158.       begin                               { place character in buffer }
  159.         if icom_buffsize < icom_bufflimit then
  160.           begin
  161.             icom_portbuffer[icom_buffend] := Chr(Port[boi_portadd + RBRoff]);
  162.             if icom_buffend < icom_bufflimit then
  163.                 Inc(icom_buffend)
  164.             else icom_buffend := 1;
  165.             Inc(icom_buffsize)
  166.           end
  167.         else LSRstatus := Port[boi_portadd + RBRoff] { clear LSR status byte }
  168.       end
  169. {   else CallOldInt(asyncvector); } { call previous interrupt for processing }
  170.     else if ((IIRstatus and $06) = $06) then
  171.         LSRstatus := Port[boi_portadd + RBRoff];
  172.     if boi_tintr then BOI_Safe;
  173.     Inline($FA);   { CLI }
  174.     Port[PICCMD] := $20;                      { reset 8259A PIC }
  175.     if boi_cascade then Port[PIC2CMD] := $20  { reset cascade 8259A PIC }
  176.   end;  {* AsyncInt *}
  177.  
  178. Procedure SENDCHAR(outchar : char);
  179.   var
  180.     charsent : boolean;
  181.  
  182.   begin {* SendChar *}
  183.     boi_stall := 1;
  184.     case boi_cmode of
  185.         com_internal :
  186.           begin
  187.             while (port[boi_portadd + LSRoff] and
  188.                 RTSbit <> RTSbit) or   { <- UART ready }
  189.                 ({ baudlock and } { /B switch is now assumed }
  190.                 (port[boi_portadd + MSRoff] and CTSbit <> CTSbit)) do
  191.               begin                           { ^^ modem ready ^^ }
  192.                 if not in_dos^ then BOI_Wait;
  193.                 if not Carrier then DoTimeOut(false)
  194.                 else if boi_stall >= 1092 then DoTimeOut(false)
  195.                        { timeout after 60 seconds, assume carrier is lost }
  196.               end;
  197.             port[boi_portadd + RBRoff] := Ord(outchar)  { send character }
  198.           end;
  199.         com_fossil :
  200.           begin
  201.             repeat
  202.               begin
  203.                 foss_regs.AH := $0B;
  204.                 foss_regs.AL := Ord(outchar);
  205.                 foss_regs.DX := boi_portnum;
  206.                 Intr(fossint,foss_regs);
  207.                 charsent := foss_regs.AX = $0001;
  208.                 if not charsent then
  209.                   begin
  210.                     if (not Carrier) or (boi_stall > 1092) then
  211.                         DoTimeOut(false);
  212.                     if not in_dos^ then BOI_Wait
  213.                   end
  214.               end
  215.             until charsent
  216.           end
  217.       end
  218.   end;  {* SendChar *}
  219.  
  220. Function CHARREADY : boolean;
  221.   begin {* fCharReady *}
  222.     case boi_cmode of
  223.         com_internal : CharReady := icom_buffsize > 0;
  224.         com_fossil :
  225.           begin
  226.             foss_regs.AH := $03;
  227.             foss_regs.DX := boi_portnum;
  228.             Intr(fossint,foss_regs);
  229.             CharReady := foss_regs.AH and $01 = $01
  230.           end
  231.       end
  232.   end;  {* fCharReady *}
  233.  
  234. Function READBUFFER : char;
  235.   var
  236.     rb : char;
  237.  
  238.   begin {* fReadBuffer *}
  239.     if CharReady then case boi_cmode of
  240.         com_internal :
  241.           begin
  242.             rb := icom_portbuffer[icom_buffstart];
  243.             if icom_buffstart < icom_bufflimit then
  244.                 Inc(icom_buffstart) else icom_buffstart := 1;
  245.             Dec(icom_buffsize);
  246.             ReadBuffer := rb
  247.           end;
  248.         com_fossil :
  249.           begin
  250.             foss_regs.AH := $02;
  251.             foss_regs.DX := boi_portnum;
  252.             Intr(fossint,foss_regs);
  253.             ReadBuffer := Chr(foss_regs.AL)
  254.           end
  255.       end
  256.     else ReadBuffer := null
  257.   end;  {* fReadBuffer *}
  258.  
  259. Procedure CLEARINBUFFER;
  260.   begin {* ClearInBuffer *}
  261.     case boi_cmode of
  262.         com_internal :
  263.           begin
  264.             icom_buffend := icom_buffstart;
  265.             icom_buffsize := 0
  266.           end;
  267.         com_fossil :
  268.           begin
  269.             foss_regs.AH := $0A;
  270.             foss_regs.DX := boi_portnum;
  271.             Intr(fossint,foss_regs)
  272.           end
  273.       end
  274.   end;  {* ClearInBuffer *}
  275.  
  276. Procedure SETBUFFERSIZE(newsize : integer);
  277.   begin {* SetBufferSize *}
  278.     if (newsize > 1) and (newsize <= icom_maxbuff) then
  279.       begin
  280.         icom_buffstart := 1;
  281.         ClearInBuffer;
  282.         icom_bufflimit := newsize
  283.       end;
  284.   end;  {* SetBufferSize *}
  285.  
  286. var
  287.   intexit : pointer;
  288.  
  289. Procedure ASYNCEND;
  290.   begin {* AsyncEnd *}
  291.     exitproc := intexit;
  292.     Inline($FA);  { CLI }
  293. {}  boi_portstatus := false;
  294.     SetIntVec(boi_portint,icom_asyncvector); { re-install old interrupt vector }
  295.     Port[PICCMD] := $20;                      { reset 8259A PIC }
  296.     if boi_cascade then Port[PIC2CMD] := $20; { reset cascade 8259A PIC }
  297.     Inline($FB)   { STI }
  298.   end;  {* AsyncEnd *}
  299.  
  300. Procedure FOSSILEND;
  301.   begin {* FOSSILEnd *}
  302.     exitproc := intexit;
  303.     foss_regs.AH := $05;
  304.     foss_regs.DX := boi_portnum;
  305.     Intr(fossint,foss_regs)
  306.   end;  {* FOSSILEnd *}
  307.  
  308. Function INTINIT : byte;
  309.   var
  310.     initerr : byte;
  311.  
  312.   Procedure ASYNCINIT;
  313.     var
  314.       inittemp : byte;                 { temporary data holding variable }
  315.  
  316.     begin {* fIntInit,AsyncInit *}
  317.       intexit := exitproc;
  318.       exitproc := @AsyncEnd;
  319.       FillChar(icom_portbuffer,SizeOf(icom_portbuffer),32);
  320.       icom_buffend   := 1;
  321.       icom_buffstart := 1;
  322.       icom_buffsize  := 0;
  323.       icom_bufflimit := icom_maxbuff;
  324.   {}  boi_portstatus := true;
  325.       GetIntVec(boi_portint,icom_asyncvector);  { save old interrupt vector }
  326.       SetIntVec(boi_portint,@AsyncInt);         { install AsyncInt vector }
  327.       boi_cmode := com_internal;
  328.       boi_cstr := ' Internal Comm Active';
  329.       Port[PICMSK] := Port[PICMSK] and boi_picmask;  { access 8259A PIC }
  330.       if boi_cascade then
  331.           Port[PIC2MSK] := Port[PIC2MSK] and boi_pic2msk;
  332.       Port[boi_portadd + LCRoff] := Port[boi_portadd + LCRoff] and $7F;
  333.                                             { disable divisor latch register }
  334.       Port[boi_portadd + IERoff] := $01;        { enable interrupts }
  335.       Port[boi_portadd + MCRoff] := $0B;        { set RTS, DTR and OUT2 }
  336.   {   Port[boi_portadd + MSRoff] := $80; }      {}
  337.       inittemp := Port[boi_portadd + LSRoff];   { reset LSR }
  338.       Port[PICCMD] := $20;                     { reset 8259A PIC }
  339.       if boi_cascade then Port[PIC2CMD] := $20 { reset cascade 8259A PIC }
  340.     end;  {* fIntInit,AsyncInit *}
  341.  
  342.   Procedure FOSSILINIT;
  343.     type
  344.       charray  = array [1..80] of char;
  345.  
  346.       inforec  = record
  347.           stuff : longint;
  348.           idstr : ^charray
  349.         end;
  350.  
  351.     var
  352.       fossbuff : ^inforec;
  353.  
  354.     begin {* FOSSILInit *}
  355.       if foss_init AND $04 = $04 then
  356.         begin
  357.           intexit := exitproc;
  358.           exitproc := @FOSSILEnd
  359.         end;
  360.       boi_cmode := com_fossil;
  361.       ClearInBuffer;
  362.       New(fossbuff);
  363.       foss_regs.AH := $1B;
  364.       foss_regs.CX := 8;
  365.       foss_regs.DX := boi_portnum;
  366.       foss_regs.ES := ptrmask(fossbuff).pseg;
  367.       foss_regs.DI := ptrmask(fossbuff).poff;
  368.       Intr(fossint,foss_regs);
  369.       Move(fossbuff^.idstr^,boi_cstr[2],78);
  370.       boi_cstr[0] := #80;
  371.       boi_cstr[1] := ' ';
  372.       boi_cstr[0] := Chr(Pos(#00,boi_cstr) - 1);
  373.       Dispose(fossbuff)
  374.     end;  {* FOSSILInit *}
  375.  
  376.   begin {* fIntInit *}
  377.     initerr := 0;
  378.     if foss_init AND $01 = $01 then AsyncInit
  379.     else
  380.       begin
  381.         foss_regs.AH := $04;
  382.         foss_regs.DX := boi_portnum;
  383.         Intr(fossint,foss_regs);
  384. {       fossrev  := regs.bh;           { FOSSIL version implemented        }
  385. {       fossfunc := regs.bl            { highest FOSSIL function supported }
  386.         if foss_regs.AX = $1954 then FOSSILInit
  387.         else if foss_init AND $02 <> $02 then AsyncInit
  388.         else initerr := 31
  389.       end;
  390.     IntInit := initerr
  391.   end;  {* fIntInit *}
  392.  
  393. begin {* uAsync *}
  394. end.  {* uAsync *}
  395.